package com.yys.excel.yysexcel.utils.dbUtil;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.*;
import cn.hutool.db.ds.simple.SimpleDataSource;
import cn.hutool.db.handler.RsHandler;
import cn.hutool.db.sql.Direction;
import cn.hutool.db.sql.Order;
import cn.hutool.db.sql.SqlBuilder;
import com.yys.excel.yysexcel.common.constant.ExcelStants;
import com.yys.excel.yysexcel.common.enums.ErrorStatus;
import com.yys.excel.yysexcel.common.exception.CustomException;
import com.yys.excel.yysexcel.common.exception.ServiceException;
import com.yys.excel.yysexcel.entity.ImportExportTemplate;
import com.yys.excel.yysexcel.entity.JdbcConfig;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

public class DbUtil {

    static {
        GlobalDbConfig.setCaseInsensitive(false);
    }

    public static void main(String[] args) throws SQLException {
        ImportExportTemplate importExportTemplate = new ImportExportTemplate();
        importExportTemplate.setFile_path("xlsx");

        Entity entity = BeanUtil.toBean(importExportTemplate, Entity.class).setTableName(ImportExportTemplate.getTableName());
        entity.remove("id");
        DbUtil.insert(entity);


        System.out.println();




    }

    /**
     * 获取数据来源
     *
     * @param jdbcConfig jdbc域
     * @return {@link DataSource}
     */
    public static DataSource getDataSource(JdbcConfig jdbcConfig) {
        if (jdbcConfig == null) {
            throw new ServiceException(ErrorStatus.EXCEPTION.getCode(), "数据库配置为空");
        }
        if (StrUtil.isBlank(jdbcConfig.getType())) {
            throw new ServiceException(ErrorStatus.EXCEPTION.getCode(), "连接数据库类型未知");
        }
        if (StrUtil.isBlank(jdbcConfig.getIp()) || StrUtil.isBlank(jdbcConfig.getPort()) || StrUtil.isBlank(jdbcConfig.getDatabase_name())) {
            throw new ServiceException(ErrorStatus.EXCEPTION.getCode(), "连接数据库ip、端口或库名为空");
        }
        String userName = jdbcConfig.getUser_name();
        String passWord = jdbcConfig.getPassword();
        if (StrUtil.isBlank(userName) || StrUtil.isBlank(passWord)) {
            throw new ServiceException(ErrorStatus.EXCEPTION.getCode(), "连接数据库用户名密码存在空值");
        }
        String dbUrl = null;
        String type = jdbcConfig.getType();
        if (StrUtil.equalsIgnoreCase("mysql", type)) {
            dbUrl = "jdbc:mysql://" + jdbcConfig.getIp() + ":" + jdbcConfig.getPort() + "/" + jdbcConfig.getDatabase_name() + "?useUnicode=true&characterEncoding=utf8" +
                    "&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowMultiQueries=true";
        }
        //jdk17连接sqlserver会失败
        else if (StrUtil.equalsIgnoreCase("sqlserver", jdbcConfig.getType())) {
            dbUrl = "jdbc:sqlserver://" + jdbcConfig.getIp() + ":" + jdbcConfig.getPort() + ";databasename=" + jdbcConfig.getDatabase_name();
        } else {
            throw new ServiceException(ErrorStatus.EXCEPTION.getCode(), "只支持mysql数据库类型导入导出");
        }
        return new SimpleDataSource(dbUrl, userName, passWord);
    }

    /**
     * 获取page
     *
     * @param where 在哪里
     * @return {@link Page}
     */
    public static Page getPage(Entity where) {
        Integer pageNumber = where.getInt(ExcelStants.PAGE_NUMBER);
        if (pageNumber == null || pageNumber < 0) {
            pageNumber = 0;
        } else {
            pageNumber--;
        }
        Integer pageSize = Convert.toInt(where.getInt(ExcelStants.PAGE_SIZE), 10);
        Page page = Page.of(pageNumber, pageSize);
        //排序
        Order order = new Order();
        order.setField("create_time");
        order.setDirection(Direction.DESC);
        page.setOrder(order);
        where.remove(ExcelStants.PAGE_NUMBER);
        where.remove(ExcelStants.PAGE_SIZE);
        return page;
    }

    /**
     * 找到两个表包含的字段
     *
     * @param table1 表1
     * @param table2 表二
     */
    public static void findTwoTableContains(String table1, String table2) {
        List<String> table1Fileds = getTableFiled(table1);
        List<String> table2Fileds = getTableFiled(table2);
        List<String> list = ListUtil.list(true);
        for (String field : table1Fileds) {
            boolean contains = table2Fileds.contains(field);
            if (contains) {
                list.add(field);
            }
        }
//        StringBuilder builder = StrUtil.builder();
//        for (String s : list) {
//            builder.append("d." + s + ",");
//        }
        System.out.println();
    }

    /**
     * 获取表字段
     *
     * @param tableName 表名
     * @return {@link List}<{@link String}>
     */
    public static List<String> getTableFiled(String tableName) {
        String sql = "SELECT CASE WHEN col.colorder =1 THEN obj.name ELSE '' END AS 表名,col.colorder AS 序号 ,col.name AS 列名 ,ISNULL(ep.[value],'') AS 列说明 ,t.name AS 数据类型 ,col.length AS 长度 ,ISNULL(COLUMNPROPERTY(col.id,col.name,'Scale'),0) AS 小数位数 ,CASE WHEN COLUMNPROPERTY(col.id,col.name,'IsIdentity')=1 THEN '√' ELSE '' END AS 标识 ,CASE WHEN EXISTS ( " +
                "SELECT 1 FROM dbo.sysindexes si INNER JOIN dbo.sysindexkeys sik ON si.id =sik.id AND si.indid =sik.indid INNER JOIN dbo.syscolumns sc ON sc.id =sik.id AND sc.colid =sik.colid INNER JOIN dbo.sysobjects so ON so.name =si.name AND so.xtype ='PK' WHERE sc.id =col.id AND sc.colid =col.colid) THEN '√' ELSE '' END AS 主键 ,CASE WHEN col.isnullable =1 THEN '√' ELSE '' END AS 允许空 ,ISNULL(comm.text,'') AS 默认值 FROM dbo.syscolumns col" +
                " LEFT JOIN dbo.systypes t ON col.xtype =t.xusertype INNER JOIN dbo.sysobjects obj ON col.id =obj.id AND obj.xtype ='U' AND obj.status >=0 LEFT JOIN dbo.syscomments comm ON col.cdefault =comm.id LEFT JOIN sys.extended_properties ep ON col.id =ep.major_id AND col.colid =ep.minor_id AND ep.name ='MS_Description' LEFT JOIN sys.extended_properties epTwo ON obj.id =epTwo.major_id AND epTwo.minor_id =0 AND epTwo.name ='MS_Description' WHERE obj.name ='" + tableName + "' ORDER BY col.colorder";
        try {
            List<Entity> query = getDb().query(sql);
            return query.stream().map(e -> {
                return e.getStr("列名");
            }).collect(Collectors.toList());
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return null;
    }

    /**
     * 更新
     *
     * @param record 记录
     * @param where  在哪里
     * @return int
     */
    public static int update(Entity record, Entity where) {
        try {
            return getDb().update(record, where);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 插入
     *
     * @param records 记录
     * @return int
     */
    public static int[] insert(Collection<Entity> records) {
        try {
            return getDb().insert(records);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return new int[]{-1};
    }

    /**
     * 插入
     *
     * @param record 记录
     * @return int
     */
    public static int insert(Entity record) {
        try {
            return getDb().insert(record);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return -1;
    }

    /**
     * 查询
     *
     * @param sql    查询语句
     * @param params 参数
     * @return 结果对象
     * @throws SQLException SQL执行异常
     * @since 3.1.1
     */
    public static List<Entity> querys(String sql, Object... params) {
        try {
            return getDb().query(sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询单条记录
     *
     * @param sql    查询语句
     * @param params 参数
     * @return 结果对象
     * @throws SQLException SQL执行异常
     */
    public static Entity query(String sql, Object... params) {
        try {
            return getDb().queryOne(sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 执行非查询语句<br>
     * 语句包括 插入、更新、删除
     *
     * @param sql    SQL
     * @param params 参数
     * @return 影响行数
     * @throws SQLException SQL执行异常
     */
    public static int execute(String sql, Object... params) {
        try {
            return getDb().execute(sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 分页查询<br>
     * 查询条件为多个key value对表示，默认key = value，如果使用其它条件可以使用：where.put("key", " &gt; 1")，value也可以传Condition对象，key被忽略
     *
     * @param <T>        结果对象类型
     * @param fields     返回的字段列表，null则返回所有字段
     * @param where      条件实体类（包含表名）
     * @param page       页码，0表示第一页
     * @param numPerPage 每页条目数
     * @param rsh        结果集处理对象
     * @return 结果对象
     * @throws SQLException SQL执行异常
     */
    public static <T> T page(Collection<String> fields, Entity where, int page, int numPerPage, RsHandler<T> rsh) {
        try {
            return getDb().page(fields, where, page, numPerPage, rsh);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分页查询<br>
     * 查询条件为多个key value对表示，默认key = value，如果使用其它条件可以使用：where.put("key", " &gt; 1")，value也可以传Condition对象，key被忽略
     *
     * @param <T>        结果对象类型
     * @param where      条件实体类（包含表名）
     * @param page       页码，0表示第一页
     * @param numPerPage 每页条目数
     * @param rsh        结果集处理对象
     * @return 结果对象
     * @throws SQLException SQL执行异常
     * @since 3.2.2
     */
    public static <T> T page(Entity where, int page, int numPerPage, RsHandler<T> rsh) {
        try {
            return getDb().page(where, page, numPerPage, rsh);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分页查询<br>
     * 查询条件为多个key value对表示，默认key = value，如果使用其它条件可以使用：where.put("key", " &gt; 1")，value也可以传Condition对象，key被忽略
     *
     * @param <T>   结果对象类型
     * @param where 条件实体类（包含表名）
     * @param page  分页对象
     * @param rsh   结果集处理对象
     * @return 结果对象
     * @throws SQLException SQL执行异常
     * @since 3.2.2
     */
    public static <T> T page(Entity where, Page page, RsHandler<T> rsh) {
        try {
            return getDb().page(where, page, rsh);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分页查询<br>
     * 查询条件为多个key value对表示，默认key = value，如果使用其它条件可以使用：where.put("key", " &gt; 1")，value也可以传Condition对象，key被忽略
     *
     * @param <T>    结果对象类型
     * @param fields 返回的字段列表，null则返回所有字段
     * @param where  条件实体类（包含表名）
     * @param page   分页对象
     * @param rsh    结果集处理对象
     * @return 结果对象
     * @throws SQLException SQL执行异常
     */
    public static <T> T page(Collection<String> fields, Entity where, Page page, RsHandler<T> rsh) {
        try {
            return getDb().page(fields, where, page, rsh);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分页查询<br>
     *
     * @param <T>    结果对象类型
     * @param sql    SQL构建器，可以使用{@link SqlBuilder#of(CharSequence)} 包装普通SQL
     * @param page   分页对象
     * @param rsh    结果集处理对象
     * @param params 参数
     * @return 结果对象
     * @throws SQLException SQL执行异常
     * @since 5.6.6
     */
    public static <T> T page(CharSequence sql, Page page, RsHandler<T> rsh, Object... params) {
        try {
            return getDb().page(sql, page, rsh, params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分页查询
     *
     * @param <T>  处理结果类型，可以将ResultSet转换为给定类型
     * @param sql  SQL构建器
     * @param page 分页对象
     * @param rsh  结果集处理对象
     * @return 结果对象
     * @throws SQLException SQL执行异常
     */
    public static <T> T page(SqlBuilder sql, Page page, RsHandler<T> rsh) {
        try {
            return getDb().page(sql, page, rsh);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分页查询
     *
     * @param sql    SQL语句字符串
     * @param page   分页对象
     * @param params 参数列表
     * @return 结果对象
     * @throws SQLException SQL执行异常
     * @since 5.5.3
     */
    public static PageResult<Entity> page(CharSequence sql, Page page, Object... params) {
        try {
            return getDb().page(sql, page, params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分页查询
     *
     * @param sql      SQL语句字符串
     * @param pageNum  页数
     * @param pageSize 页码大小
     * @param params   参数列表
     * @return 结果对象
     * @throws SQLException SQL执行异常
     * @since 5.5.3
     */
    public static PageResult<Entity> page(CharSequence sql, int pageNum, int pageSize, Object... params) {
        try {
            return getDb().page(sql, new Page(pageNum, pageSize), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分页查询<br>
     * 查询条件为多个key value对表示，默认key = value，如果使用其它条件可以使用：where.put("key", " &gt; 1")，value也可以传Condition对象，key被忽略
     *
     * @param fields     返回的字段列表，null则返回所有字段
     * @param where      条件实体类（包含表名）
     * @param pageNumber 页码
     * @param pageSize   每页结果数
     * @return 结果对象
     * @throws SQLException SQL执行异常
     */
    public static PageResult<Entity> page(Collection<String> fields, Entity where, int pageNumber, int pageSize) {
        try {
            return getDb().page(fields, where, pageNumber, pageSize);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分页查询<br>
     * 查询条件为多个key value对表示，默认key = value，如果使用其它条件可以使用：where.put("key", " &gt; 1")，value也可以传Condition对象，key被忽略
     *
     * @param fields 返回的字段列表，null则返回所有字段
     * @param where  条件实体类（包含表名）
     * @param page   分页对象
     * @return 结果对象
     * @throws SQLException SQL执行异常
     */
    public static PageResult<Entity> page(Collection<String> fields, Entity where, Page page) {
        try {
            return getDb().page(fields, where, page);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分页查询<br>
     * 查询条件为多个key value对表示，默认key = value，如果使用其它条件可以使用：where.put("key", " &gt; 1")，value也可以传Condition对象，key被忽略
     *
     * @param where      条件实体类（包含表名）
     * @param page       页码
     * @param numPerPage 每页条目数
     * @return 分页结果集
     * @throws SQLException SQL执行异常
     * @since 3.2.2
     */
    public static PageResult<Entity> page(Entity where, int page, int numPerPage) {
        try {
            return getDb().page(where, page, numPerPage);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分页查询<br>
     * 查询条件为多个key value对表示，默认key = value，如果使用其它条件可以使用：where.put("key", " &gt; 1")，value也可以传Condition对象，key被忽略
     *
     * @param where 条件实体类（包含表名）
     * @param page  分页对象
     * @return 分页结果集
     * @throws SQLException SQL执行异常
     */
    public static PageResult<Entity> page(Entity where, Page page) {
        try {
            return getDb().page(where, page);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Db getDb() {
        return Db.use();
    }

    public static Db getDb(JdbcConfig jdbcConfig) {
        return Db.use(getDataSource(jdbcConfig));
    }
}
